package com.codescan.admin.modules.codescan.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codescan.admin.common.exception.ApiException;
import com.codescan.admin.modules.codescan.mapper.SourceReportMapper;
import com.codescan.admin.modules.codescan.model.SourceReportVo;
import com.codescan.admin.modules.codescan.service.ISourceReportService;
import com.codescan.admin.modules.codescan.vo.SourceOrigin;
import com.codescan.admin.modules.codescan.vo.SourceReport;
import com.codescan.admin.modules.sys.model.SysFile;
import com.codescan.admin.modules.sys.service.IFileService;
import com.codescan.admin.utils.PdfReport;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class SourceReportServiceImpl extends ServiceImpl<SourceReportMapper, SourceReportVo> implements ISourceReportService {
    @Autowired
    private IFileService fileService;
    @Value("${output.filepath}")
    private String outputFilepath;
    @Value("${xssMap.filepath}")
    private String xssMapPath;
    @Override
    public boolean saveReport(SourceReportVo sourceReportVo) {
        String suffiixName = sourceReportVo.getCodePath().substring(sourceReportVo.getCodePath().lastIndexOf("."));
        sourceReportVo.setStatus("loading");
        sourceReportVo.setUploadtime(new Date());
        boolean flag = this.save(sourceReportVo);
        if(suffiixName.equalsIgnoreCase(".json")) {
            SysFile sysFile = fileService.findByMinioUrl(sourceReportVo.getCodePath());
            if (Objects.isNull(sysFile)) {
                throw new ApiException("获取文件信息失败!");
            }
            new Thread(() -> analysisSourceCode(sourceReportVo, sysFile)).start();
        }else {
            throw new ApiException("请上传json格式的文件!");
        }

        return flag;
    }


    private void analysisSourceCode(SourceReportVo sourceReportVo, SysFile sysFile) {
        String localPath = sysFile.getLocalUrl();
        File file = new File(localPath);
        if(!file.exists()){
            throw new ApiException("获取文件信息失败!");
        }
        this.execPython(localPath ,sourceReportVo);
    }

    private void execPython(String localPath, SourceReportVo sourceReportVo) {
        String resultFilePath = outputFilepath + new Date().getTime() + ".json";
        try {
//            String filename = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "python-script/XssMap.py").getPath();
            String execCommand = "python3 " + xssMapPath + " " + localPath + " " + resultFilePath;
            log.info("python命令为:{}",execCommand);
            Process process = Runtime.getRuntime().exec(execCommand);
            process.waitFor();

            SourceOrigin sourceOrigin = this.getSourceOriginData(localPath);
            if(Objects.nonNull(sourceOrigin)){
                SourceReport sourceReport = this.createReport(resultFilePath,sourceOrigin.getRequestUrl());
                String pdfURL = this.createPdf(sourceReport);
                String url = fileService.uploadFile(pdfURL);
                log.info("localPath:{},minio url:{}",localPath,url);
                sourceReportVo.setFilePath(url);
                sourceReportVo.setStatus("done");
                this.updateById(sourceReportVo);
            }
        } catch (Exception e) {
            log.error("操作失败!",e);
            sourceReportVo.setStatus("failed");
            sourceReportVo.setReason(e.toString());
            this.updateById(sourceReportVo);
        }

    }

    private SourceOrigin  getSourceOriginData(String originPath){
        String jsonStr = "";
        try {
            File jsonFile = new File(originPath);
            FileReader fileReader = new FileReader(jsonFile);
            Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            SourceOrigin sourceOrigin = JSONObject.parseObject(jsonStr,SourceOrigin.class);
            return sourceOrigin;
        }catch (Exception e){
            log.error("获取源码失败！");
            throw new ApiException("获取源码失败！");
        }
    }
    private SourceReport createReport(String resultPathUrl,String targetUrl){
        String jsonStr = "";
        try{
            File jsonFile = new File(resultPathUrl);
            FileReader fileReader = new FileReader(jsonFile);
            Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            SourceReport sourceReport = JSONObject.parseObject(jsonStr, SourceReport.class);
            sourceReport.setTargetUrl(targetUrl);
//            log.info("================{}",sourceReport.toString());
            return sourceReport;
        }catch (Exception e){
            log.error("生成报告失败！");
            throw new ApiException("生成报告失败");
        }
    }

    @Override
    public String createPdf(SourceReport sourceReport){
        try {
            // 1.新建document对象
            Document document = new Document(PageSize.A4);// 建立一个Document对象
            String pdfurl = outputFilepath + System.currentTimeMillis() + ".pdf";
            // 2.建立一个书写器(Writer)与document对象关联
            File file = new File(pdfurl);
            file.createNewFile();
            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
//            writer.setPageEvent(new Watermark("HELLO ITEXTPDF"));// 水印
//            writer.setPageEvent(new MyHeaderFooter());// 页眉/页脚

            // 3.打开文档
            document.open();
//            document.addTitle("Title@PDF-Java");// 标题
//            document.addAuthor("Author@umiz");// 作者
//            document.addSubject("Subject@iText pdf sample");// 主题
//            document.addKeywords("Keywords@iTextpdf");// 关键字
//            document.addCreator("Creator@umiz`s");// 创建者

            // 4.向文档中添加内容
            new PdfReport().generatePDF(document,sourceReport);

            // 5.关闭文档
            document.close();
            return pdfurl;
        } catch (Exception e) {
            log.error("生成报告失败！");
            return null;
        }
    }
}
